package cn.apthink.calendar;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import lombok.Data;

@Data
public class Day {
	private List<TimeRange> timeRanges;
	private int duration = 0;
	private int durationNormal = 0;

	public int getDurationOvertime() {
		return duration - durationNormal;
	}

	public int calcDuration(int start, int end) {
		if (start <= getStart() && end >= getEnd()) {
			return getDuration();
		} else if (end <= getStart() || start >= getEnd()) {
			return 0;
		} else {
			int d = 0;
			for (TimeRange x : timeRanges) {
				long s = start > x.getStart() ? start : x.getStart();
				long e = end > x.getEnd() ? x.getEnd() : end;
				if (s < e) {
					d += e - s;
				}
			}
			return d;
		}
	}

	public int getValid(int current) {
		return getValid(current, 0);
	}

	public int getValid(int start, int offSecond) {
		int len = this.timeRanges.size();
		int i;
		for (i = 0; i < len; i++) {
			if (this.timeRanges.get(i).getEnd() > start)
				break;
		}
		if (i < len) {
			int off = offSecond;
			if (this.timeRanges.get(i).getStart() >= start) {
				if (offSecond == 0)
					return this.timeRanges.get(i).getStart();
			} else {
				if (offSecond == 0)
					return start;
				else {
					int s = this.timeRanges.get(i).getEnd() - start;
					if (s > offSecond) {
						return start + offSecond;
					} else {
						off -= s;
						i++;
					}
				}
			}
			for (; i < len; i++) {
				if (off > timeRanges.get(i).duration()) {
					off -= timeRanges.get(i).duration();
				} else {
					return timeRanges.get(i).getStart() + off;
				}
			}
		}
		return getEnd();
	}

	public int getStart() {
		return timeRanges.get(0).getStart();
	}

	public int getEnd() {
		return timeRanges.get(timeRanges.size() - 1).getEnd();
	}

	private void _sort() {
		this.timeRanges.sort((a, b) -> {
			return a.getStart() - b.getStart();
		});
	}

	public void addTimeRange(TimeRange timeRange) {
		if (Objects.isNull(timeRanges)) {
			timeRanges = new ArrayList<TimeRange>();
		}
		if (!Objects.isNull(timeRange)) {
			duration += timeRange.duration();
			durationNormal += !timeRange.isOvertime() ? timeRange.duration() : 0;
			timeRanges.add(timeRange);
			_sort();
		}
	}

	public void setTimeRanges(List<TimeRange> timeRanges) {
		duration = 0;
		durationNormal = 0;
		this.timeRanges = timeRanges;
		if (!Objects.isNull(timeRanges)) {
			this.timeRanges.forEach(x -> {
				duration += x.duration();
				durationNormal += !x.isOvertime() ? x.duration() : 0;
			});
			_sort();
		}
	}

	public String startHM() {
		return timeRanges.get(0).startHM();
	}

	public String endHM() {
		return timeRanges.get(timeRanges.size() - 1).endHM();
	}

	public String startHMS() {
		return timeRanges.get(0).startHMS();
	}

	public String endHMS() {
		return timeRanges.get(timeRanges.size() - 1).endHMS();
	}

	@Override
	public int hashCode() {
		return Objects.hash(duration, timeRanges);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Day other = (Day) obj;
		return duration == other.duration && Objects.equals(timeRanges, other.timeRanges);
	}

	public static Day testData() {
		Day day = new Day();
		TimeRange tr = DayTimeHelper.getTimeRange("8:00", "12:00", false);
		day.addTimeRange(tr);
		tr = DayTimeHelper.getTimeRange("13:00", "17:00", false);
		day.addTimeRange(tr);
		tr = DayTimeHelper.getTimeRange("19:00", "21:00", true);
		day.addTimeRange(tr);
		return day;
	}

}
